Skip to contentMethod: createForSimpleList(Connector, ValueFactory)
1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.ontodriver.sesame;
16:
17: import java.util.ArrayList;
18: import java.util.Collection;
19: import java.util.List;
20:
21: import cz.cvut.kbss.ontodriver.model.NamedResource;
22: import org.openrdf.model.Resource;
23: import org.openrdf.model.Statement;
24: import org.openrdf.model.URI;
25: import org.openrdf.model.Value;
26: import org.openrdf.model.ValueFactory;
27:
28: import cz.cvut.kbss.ontodriver.exception.IntegrityConstraintViolatedException;
29: import cz.cvut.kbss.ontodriver.sesame.connector.Connector;
30: import cz.cvut.kbss.ontodriver.sesame.exceptions.SesameDriverException;
31: import cz.cvut.kbss.ontodriver.descriptor.ListDescriptor;
32: import cz.cvut.kbss.ontodriver.descriptor.ListValueDescriptor;
33: import cz.cvut.kbss.ontodriver.descriptor.ReferencedListDescriptor;
34: import cz.cvut.kbss.ontodriver.descriptor.ReferencedListValueDescriptor;
35: import cz.cvut.kbss.ontodriver.descriptor.SimpleListDescriptor;
36: import cz.cvut.kbss.ontodriver.descriptor.SimpleListValueDescriptor;
37: import cz.cvut.kbss.ontodriver.model.Axiom;
38:
39: /**
40: * Base class for list handlers. </p>
41: *
42: * List handlers are responsible for loading and persisting lists.
43: *
44: * @author ledvima1
45: *
46: * @param <T>
47: * List descriptor type
48: * @param <V>
49: * List value descriptor type
50: */
51: abstract class ListHandler<T extends ListDescriptor, V extends ListValueDescriptor> {
52:
53:         protected final Connector connector;
54:         protected final ValueFactory vf;
55:
56:         ListHandler(Connector connector, ValueFactory vf) {
57:                 this.connector = connector;
58:                 this.vf = vf;
59:         }
60:
61:         /**
62:          * Loads axioms representing list described by the specified list
63:          * descriptor.
64:          *
65:          * @return Collection of axioms representing sequence values
66:          * @throws SesameDriverException
67:          */
68:         List<Axiom<NamedResource>> loadList(T listDescriptor) throws SesameDriverException {
69:                 final List<Axiom<NamedResource>> axioms = new ArrayList<>();
70:                 final SesameIterator it = createIterator(listDescriptor);
71:                 while (it.hasNext()) {
72:                         axioms.add(it.nextAxiom());
73:                 }
74:                 return axioms;
75:         }
76:
77:         abstract SesameIterator createIterator(T listDescriptor) throws SesameDriverException;
78:
79:         /**
80:          * Persists list values specified by the descriptor. </p>
81:          *
82:          * The values are saved in the order in which they appear in the descriptor.
83:          *
84:          * @param listValueDescriptor
85:          * Describes values to persist
86:          * @throws SesameDriverException
87:          */
88:         void persistList(V listValueDescriptor) throws SesameDriverException {
89:                 if (listValueDescriptor.getValues().isEmpty()) {
90:                         return;
91:                 }
92:                 final Collection<Statement> statements = new ArrayList<>(listValueDescriptor.getValues()
93:                                 .size());
94:                 final URI head = createListHead(listValueDescriptor, statements);
95:                 statements.addAll(createListRest(head, listValueDescriptor));
96:                 connector.addStatements(statements);
97:         }
98:
99:         abstract URI createListHead(V valueDescriptor, Collection<Statement> listStatements) throws SesameDriverException;
100:
101:         abstract List<Statement> createListRest(URI head, V valueDescriptor) throws SesameDriverException;
102:
103:         /**
104:          * Updates list with values specified by the descriptor. </p>
105:          *
106:          * @param listValueDescriptor
107:          * Describes the updated values
108:          * @throws SesameDriverException
109:          */
110:         void updateList(V listValueDescriptor) throws SesameDriverException {
111:                 if (listValueDescriptor.getValues().isEmpty()) {
112:                         clearList(listValueDescriptor);
113:                 } else if (isOldListEmpty(owner(listValueDescriptor), hasList(listValueDescriptor),
114:                                 listValueDescriptor.getListProperty().isInferred(), context(listValueDescriptor))) {
115:                         persistList(listValueDescriptor);
116:                 } else {
117:                         mergeList(listValueDescriptor);
118:                 }
119:         }
120:
121:         private boolean isOldListEmpty(Resource owner, URI hasListProperty, boolean includeInferred,
122:                         URI context) throws SesameDriverException {
123:                 final Collection<Statement> stmts = connector.findStatements(owner, hasListProperty, null,
124:                                 includeInferred, context);
125:                 return stmts.isEmpty();
126:         }
127:
128:         abstract void clearList(V listDescriptor) throws SesameDriverException;
129:
130:         private void mergeList(V listDescriptor) throws SesameDriverException {
131:                 final SesameIterator it = iterator(listDescriptor);
132:                 final MergeResult mergeResult = mergeWithOriginalList(listDescriptor, it);
133:                 removeObsoletes(it);
134:                 assert mergeResult.i > 0;
135:                 assert mergeResult.previous != null;
136:                 if (mergeResult.i < listDescriptor.getValues().size()) {
137:                         appendNewNodes(listDescriptor, mergeResult);
138:                 }
139:         }
140:
141:         abstract SesameIterator iterator(V listDescriptor) throws SesameDriverException;
142:
143:         abstract MergeResult mergeWithOriginalList(V listDescriptor, SesameIterator it) throws SesameDriverException;
144:
145:         abstract void appendNewNodes(V listDescriptor, MergeResult mergeResult) throws SesameDriverException;
146:
147:         void removeObsoletes(SesameIterator it) throws SesameDriverException {
148:                 while (it.hasNext()) {
149:                         it.nextNode();
150:                         it.remove();
151:                 }
152:         }
153:
154:         Resource extractListNode(Collection<Statement> stmts, URI nodeAssertion)
155:                         throws SesameDriverException {
156:                 if (stmts.size() > 1) {
157:                         throw new IntegrityConstraintViolatedException(
158:                                         "Invalid number of values found for assertion " + nodeAssertion
159:                                                         + ". Expected 1, got " + stmts.size());
160:                 }
161:                 final Value val = stmts.iterator().next().getObject();
162:                 if (!(val instanceof Resource)) {
163:                         throw new IntegrityConstraintViolatedException(
164:                                         "Invalid property value. Expected object property value, got literal.");
165:                 }
166:                 return (Resource) val;
167:         }
168:
169:         URI context(ListDescriptor listDescriptor) {
170:                 return sesameUri(listDescriptor.getContext());
171:         }
172:
173:         URI owner(ListDescriptor listDescriptor) {
174:                 return sesameUri(listDescriptor.getListOwner().getIdentifier());
175:         }
176:
177:         URI hasList(ListDescriptor listDescriptor) {
178:                 return sesameUri(listDescriptor.getListProperty().getIdentifier());
179:         }
180:
181:         URI hasNext(ListDescriptor listDescriptor) {
182:                 return sesameUri(listDescriptor.getNextNode().getIdentifier());
183:         }
184:
185:         URI sesameUri(java.net.URI uri) {
186:                 return SesameUtils.toSesameUri(uri, vf);
187:         }
188:
189:         /**
190:          * Creates handler for simple lists.
191:          *
192:          * @param connector
193:          * Storage connector
194:          * @param vf
195:          * Sesame value factory
196:          * @return List handler
197:          */
198:         static ListHandler<SimpleListDescriptor, SimpleListValueDescriptor> createForSimpleList(
199:                         Connector connector, ValueFactory vf) {
200:•                assert connector != null;
201:•                assert vf != null;
202:
203:                 return new SimpleListHandler(connector, vf);
204:         }
205:
206:         /**
207:          * Creates handler for referenced lists.
208:          *
209:          * @param connector
210:          * Storage connector
211:          * @param vf
212:          * Sesame value factory
213:          * @return List handler
214:          */
215:         static ListHandler<ReferencedListDescriptor, ReferencedListValueDescriptor> createForReferencedList(
216:                         Connector connector, ValueFactory vf) {
217:                 assert connector != null;
218:                 assert vf != null;
219:
220:                 return new ReferencedListHandler(connector, vf);
221:         }
222:
223:         static final class MergeResult {
224: protected int i;
225: protected Resource previous;
226: protected MergeResult(int i, Resource node) {
227: this.i = i;
228: this.previous = node;
229: }
230: }
231: }